/* User IO implementation file */
//Faith Or

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <windows.h>
#include "model.h"
#include "lamHASH.h"
#include "controller_bstPhuc.h"
#include "UserIO.h"

#define MAX_SIZE 200
#define FLUSH while(getchar() != '\n')
#define MAX_STR 200

/* fare outputs "Thank You" message                               */
/* Pre:  none                                                     */
/* Post:   "Thank You"                                            */
/* Return: none                                                   */
/* Written by: Faith Or                                           */
void fare(void)
{
	HANDLE hCon;

	char *logo1 = "      ########   ##         ########   ########   #######    \n";
	char *logo2 = "     ##          ##         ##         ##         ##    ##   \n";
	char *logo3 = "      ##         ##         ##         ##         ##    ##   \n";
	char *logo4 = "        ###      ##         ########   ########   #######    \n";
	char *logo5 = "           ##    ##         ##         ##         ##         \n";
	char *logo6 = "            ##   ##         ##         ##         ##         \n";
	char *logo7 = "     ########    ########   ########   ########   ##         \n\n";
	
	char *logo8= "                        ##         ########    ########    ######## \n";
	char *logo9= "                        ##         ##         ##          ##        \n";
	char *logo10="                        ##         ##          ##          ##       \n";
	char *logo11="                        ##         ########      ###         ###    \n";
	char *logo12="                        ##         ##               ##          ##  \n"; 
	char *logo13="                        ##         ##                ##          ## \n";
	char *logo14="                        ########   ########   ########    ########  \n\n";

	char *logo15 = " ########   ##    ##       ##      ###      #   ##      ##   ######## \n";
	char *logo16 = "    ##      ##    ##     ## ##     # ##     #   ##     ##   ##        \n";
	char *logo17 = "    ##      ##    ##    ##   ##    #  ##    #   ##    ##     ##       \n";
	char *logo18 = "    ##      ########   ## ### ##   #   ##   #   #######        ###    \n";
	char *logo19 = "    ##      ##    ##   ##     ##   #    ##  #   ##    ##          ##  \n"; 
	char *logo20 = "    ##      ##    ##   ##     ##   #     ####   ##     ##          ## \n";
	char *logo21 = "    ##      ##    ##   ##     ##   #      ###   ##      ##   ########  \n\n";
	
	char *logo22= "           ##          ##     #####     ##     ##  ##########  \n";
	char *logo23= "             ##      ##     ##     ##   ##     ##   ########   \n";
	char *logo24= "               ##  ##       ##     ##   ##     ##    ######    \n";
	char *logo25= "                 ##         ##     ##   ##     ##     ####     \n";
	char *logo26= "                 ##         ##     ##   ##     ##      ##      \n"; 
	char *logo27= "                 ##         ##     ##   ##     ##              \n";
	char *logo28= "                 ##           #####       #####       ####     \n\n";

    hCon = GetStdHandle(STD_OUTPUT_HANDLE);


    SetConsoleTextAttribute(hCon, 2);
    rollText(logo1);
    rollText(logo2);
    SetConsoleTextAttribute(hCon, 7);
    rollText(logo3);
    rollText(logo4);
    SetConsoleTextAttribute(hCon, 2);
    rollText(logo5);
    rollText(logo6);
    rollText(logo7);
	SetConsoleTextAttribute(hCon, 7);
	rollText(logo8);
    rollText(logo9);
	SetConsoleTextAttribute(hCon, 2);
    rollText(logo10);
	rollText(logo11);
	SetConsoleTextAttribute(hCon, 7);
    rollText(logo12);
    rollText(logo13);
	rollText(logo14);
	SetConsoleTextAttribute(hCon, 2);
    rollText(logo15);
    rollText(logo16);
    SetConsoleTextAttribute(hCon, 7);
    rollText(logo17);
    rollText(logo18);
    SetConsoleTextAttribute(hCon, 2);
    rollText(logo19);
    rollText(logo20);
    rollText(logo21);
	SetConsoleTextAttribute(hCon, 7);
	rollText(logo22);
    rollText(logo23);
	SetConsoleTextAttribute(hCon, 2);
    rollText(logo24);
	rollText(logo25);
	SetConsoleTextAttribute(hCon, 7);
    rollText(logo26);
    rollText(logo27);
	rollText(logo28);

	return;

}//end fare


/* menuOption shows the options a user can do and process the choice */
/* Pre:  none                                                        */
/* Post:  display name                                               */
/* Return: none                                                      */
/* Written by: Faith Or                                              */
void menuOption(void)
{
	HANDLE hCon;
	
	hCon = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(hCon, 10);

	printf("\n\n\t-----------------------------\n");
	printf("\t|     Sleepless Database    |\n");
	printf("\t-----------------------------\n");
	printf("\nPlease make your selection:\n");
	printf("\tA. Add a New Entry\n");
	printf("\tD. Delete an Existing Entry\n");
	printf("\tS. Search for an Existing Entry\n");
	printf("\tH. List the Entries in Hash Table Sequence\n");
	printf("\tK. List the Entries in Key Sequence\n");
	printf("\tP. Print the Indented Tree\n");
	printf("\tW. Write Data to a File\n");
	printf("\tU. Undo Delete\n");
	printf("\tE. Efficiency\n");
	printf("\tQ. Quit\n");
	SetConsoleTextAttribute( hCon, 128 );
	printf("Enter your choice:");
	
	return;
}//end menuOption


/* rollText prints text in typewriter animation                      */
/* Pre:  the text string                                             */
/* Post:   prints out string to output                               */
/* Return: none                                                      */
/* Written by: Faith Or                                              */
void rollText(char *text)
{
	int i;
	int size = strlen(text);
	for(i = 0; i < size; ++i) 
	{
		printf("%c", text[i]);
		delay(2);
	}
} // end rollText

// This function delays the program for specific seconds. Ex: 1000 = 1 sec
// Input	seconds
// Return	Program is delayed

/* delay function delays the program in executing for a certain time */
/* Pre:  seconds                                                     */
/* Post: delay program execution                                     */
/* Return: none                                                      */
/* Written by: Faith Or                                              */
void delay(long seconds)
{
     clock_t time1 = clock(); // uses current clock time
     clock_t time2 = time1 + seconds;
     while(time1 < time2)
     time1 = clock();
     return;
}//end delay


/* ClearStack deletes all the data in the stack and frees them       */
/* Pre:  stack exists                                                */
/* Post: Stack is empty                                              */
/* Return: none                                                      */
/* Written by: Faith Or                                              */
void ClearStack(STACK *Ptr)
{
	SOLDIER *data;

	if(emptyStack(Ptr))
		return;
	else{

		do{
			data=popStack(Ptr);
			free(data->name);
			free(data->rank);
			free(data->division);
			free(data->jobCat);
			free(data);
			
		}while(!emptyStack(Ptr));

	}

	return;
}//end ClearStack

/* CheckEx is checks if the key string given by the user is not a    */
/* duplicate.                                                        */
/* Pre:  string,Hash and targetIndex is intitalized                  */
/* Post: checked if user's given string exists in Hash               */
/* Return: 1 if there's a duplicate and 0 if not                     */
/* Written by: Faith Or                                              */
int checkEx(char *str, HASH *pHash,int *targetIndex, int arr_size)
{
	
	int search;

	search = searchHash(pHash, str, targetIndex, arr_size);

	if(search){
		return 1;

	}else
		return 0;
	

}//end checkEx

/* CheckEx is checks if the key string given by the user is not a             */
/* duplicate.                                                                 */
/* Pre:  string, Hash and targetIndex is intitalized                          */
/* Post: if there are no conflicts, data in stack is added into Hash and Bst  */
/*       if there are conflicts by user's preference:                         */
/*       Deletes stack data or deletes existing entry and adds the stack data */
/* Return: none                                                               */
/* Written by: Faith Or                                                       */
void undoDelManager(STACK *ptr, BST *bst, HASH *pHash, int arr_size)
{
	HANDLE hCon;
	SOLDIER *data;
	int result;
	int targetIndex=0;
	char option[5];
	int count;
	int delIndex;
	SOLDIER* dataOut;

	hCon = GetStdHandle(STD_OUTPUT_HANDLE);

	if(emptyStack(ptr)){
		SetConsoleTextAttribute(hCon, 78);
		printf("There's nothing to undo!");
		SetConsoleTextAttribute(hCon, 10);
		printf("\n");
		return;
	}

	data=popStack(ptr);

	if(emptyBST (bst))
		result = 0;
	else
		result = checkEx(data->name, pHash, &targetIndex, arr_size);

	if(result){
		SetConsoleTextAttribute(hCon, 128);
		printf("Sorry, unable to undo because you've already added a NEW %s!",data->name);
		SetConsoleTextAttribute(hCon,2);
		printf("\n\n\tOLD DATA\n");
		print_data(data);

		SetConsoleTextAttribute( hCon,5);
		printf("\tNEW DATA\n");
		print_data(pHash[targetIndex].pSoldier);

		SetConsoleTextAttribute( hCon, 11 );
		printf("\nTo resolve this issue, you must choose one of them to be deleted. \nThe one that is not will exist in the database.");
		SetConsoleTextAttribute( hCon, 15 );
		printf("\nDo you want to delete the OLD data or delete the NEW data?\n Press \"O\" for the OLD data or \"N\" for the NEW data:");

		do{
			SetConsoleTextAttribute( hCon, 15 );
			scanf("%4[^\n]", option);
			FLUSH;
			count = strlen(option);
			if(count > 1)
				option[0]='A';
			else
				option[0]=toupper(option[0]);

			switch(option[0]){

				case 'O': free(data->name);
						  free(data->division);
						  free(data->jobCat);
						  free(data->rank);
						  free(data);
						  SetConsoleTextAttribute(hCon, 14);
						  printf("The OLD data has been deleted.\n");
						  break;
				case 'N': 
						  if( deleteBST (bst, pHash[targetIndex].pSoldier, &dataOut) && deleteHash(pHash,pHash[targetIndex].pSoldier->name, &delIndex, &dataOut, arr_size) ){
							 free(dataOut->name);
							 free(dataOut->division);
							 free(dataOut->jobCat);
							 free(dataOut->rank);
							 free(dataOut);
							insertHash(pHash,data->name,data, arr_size);
							insertBST(bst, data);
							SetConsoleTextAttribute(hCon, 14);
							printf("The New data has been removed\n and deleted. The OLD %s has been added at index: %d.\n",data->name,targetIndex);
						  }else
							  printf("ERROR: There's an error in deleting the NEW data!!!\n");
						 
						  break;
				default:  SetConsoleTextAttribute( hCon, 78 );
						  printf("Please enter a valid choice, either \"O\" or \"N\":");
						  option[0]='A';
						  break;
			}

		}while(option[0]=='A');
		SetConsoleTextAttribute(hCon, 15);
		return;

	}else{

		if( insertBST (bst,data) && insertHash(pHash, data->name, data, arr_size)){
			SetConsoleTextAttribute(hCon, 14);
			printf("%s has been re-inserted successfully!\n",data->name);		
			return;

		}else{
			SetConsoleTextAttribute( hCon,78);
			printf("Unable to undo because of an insertion problem.\n");
			return;		

		}//end if
	}//end if
	

	return;

}//end undoDelManager

/* searchManager searches for the person in the database given by the user    */
/* through the Hash                                                           */
/* Pre:  Hash and Bst exists                                                  */
/* Post: if found, displays the info about person                             */
/*       if not found return                                                  */
/*       if there's no data in database, return                               */
/* Return: none                                                               */
/* Written by: Faith Or                                                       */
void searchManager(HASH *pHash, BST *bst, int arr_size)
{
	int search;
	int targetIndex;
	char str[MAX_SIZE];
	HANDLE hCon;

	hCon = GetStdHandle(STD_OUTPUT_HANDLE);
	if(emptyBST (bst)){
		SetConsoleTextAttribute(hCon, 78);
		printf("Database is empty!");
		SetConsoleTextAttribute(hCon, 10);
		return;
	}

	printf("Please enter the name of the person you want to search for:");
	VerValidChr(str,1);

	search = searchHash(pHash, str, &targetIndex, arr_size);

	if(search){
		SetConsoleTextAttribute( hCon,111);
		printf("%s is found at index: %d",pHash[targetIndex].pSoldier->name,targetIndex);
		SetConsoleTextAttribute( hCon,14);
		printf("\n\n");
		print_data(pHash[targetIndex].pSoldier);
		
	}else{
		SetConsoleTextAttribute( hCon,78);
		printf("This person does not exist in our database!");
	}

	return;
}//end searchManager

/* listHashManager lists the list of data in Hash table sequence              */
/* Pre:  Hash and Bst exists                                                  */
/* Post: if there are no records return                                       */
/*       if there are, list them in array sequence                            */
/* Return: none                                                               */
/* Written by: Faith Or                                                       */
void listHashManager(HASH *pHash, BST *bst, int arr_size)
{

	HASH* pWalker; 
	HASH* pEnd;
	int i;
	HANDLE hCon;

	hCon = GetStdHandle(STD_OUTPUT_HANDLE);
	if(emptyBST (bst)){
		SetConsoleTextAttribute(hCon, 78);
		printf("Database is empty! There's nothing to print out!");
		SetConsoleTextAttribute(hCon, 10);
	}

	pEnd = pHash + arr_size;
	SetConsoleTextAttribute(hCon, 11);
	printf("Index (Probes):\tSoldier Information:\n\n");


	for( i=0, pWalker = pHash; pWalker < pEnd; i++, pWalker++)
	{
		if(pWalker->pSoldier != NULL){
			SetConsoleTextAttribute(hCon, 10);
			printf("\t%d (%d)\n", i, pWalker->probe);
			SetConsoleTextAttribute(hCon, 14);
			print_data(pWalker->pSoldier);
		}//end if
	}//end for


	return;

}//end listHashManager

/* listBstManager prints out the BST list at user's prompt           */
/* Pre:    BST list has been initialized                             */
/* Post:   list printed out to screen                                */
/* Return: none                                                      */
/* Written by: Faith Or                                              */
void listBstManager(BST* list)
{

	HANDLE hCon;

	hCon = GetStdHandle(STD_OUTPUT_HANDLE);
	if(emptyBST(list)){
		SetConsoleTextAttribute(hCon, 78);
		printf("Database is empty! There's nothing to print out!");
		SetConsoleTextAttribute(hCon, 10);
	}else{
		printf("\n");
		inOrder (list, print_data);
	}

	return;

}//end print_list

/* print_data prints the data of one structure                       */
/* Pre:    task1 exists                                              */
/* Post:   data from task1 is printed out                            */
/* Return: none                                                      */
/* Written by: Faith Or                                              */
void print_data(void* Soldier1)
{
	SOLDIER currSoldier;

	currSoldier = *(SOLDIER*)Soldier1;
	
	printf("\t\tName: %s\n", currSoldier.name);
	printf("\t\tExperience: %d\n",currSoldier.experience);
	printf("\t\tRank: %s\n", currSoldier.rank);
	printf("\t\tDivision: %s\n", currSoldier.division);
	printf("\t\tJob Category: %s\n\n", currSoldier.jobCat);

 return;

}// end print_data

/* VerValidChr  checks if user input contains valid characters       */
/* Pre: none                                                         */
/* Post: returns a vaild number                                      */
/* Return: int                                                       */
/* Written by: Faith Or                                              */
void VerValidChr(char *cpy, int option)
{

	int i;
	int count;
	int result;
	int checkNull;
	char str[MAX_SIZE];
	char concat[MAX_SIZE]="\0";
	char empty[MAX_SIZE]="\0";
	char tokens[]=" ";
	char tok2[]="& ";
	char *p;
	HANDLE hCon;
	hCon = GetStdHandle(STD_OUTPUT_HANDLE);


	do{
		checkNull = scanf("%[^\n]", str);
		FLUSH;
		if(checkNull == 1){
			
			strcpy(cpy, str);
			
			if(option==1){
				p = strtok(str, tokens);
				while(p != NULL){
				strcat(concat,p);
				p=strtok(NULL,tokens);
			    }

			}else{

				p = strtok(str, tok2);
				while(p != NULL){
				strcat(concat,p);
				p=strtok(NULL,tok2);
				}
			}

			count = strlen(concat);
			i = 0;
			while(i < count){

				if( isalpha(concat[i]) ){
					result = 1;
					i++;
				}else{
					result = 0;
					i = count;
				}
			}

		}else
			result = 0;
		if(!result){
			strcpy(concat,empty);
			SetConsoleTextAttribute(hCon, 78);
			printf("Please enter alphabetical characters: ");
			SetConsoleTextAttribute(hCon, 15);
		}
		
	}while(!result);

	return;


}// end VerValidChr

/* VerValidNum  checks if user input contains valid numbers          */
/* Pre: none                                                         */
/* Post: returns a vaild number                                      */
/* Return: int                                                       */
/* Written by: Faith Or                                              */
int VerValidNum(void)
{
	int exp=0;
	HANDLE hCon;
	hCon = GetStdHandle(STD_OUTPUT_HANDLE);

	do{
		scanf("%d",&exp);
		FLUSH;
		if(!exp){
			SetConsoleTextAttribute(hCon, 78);
			printf("Please enter an integer:");
			SetConsoleTextAttribute(hCon, 15);
		}

	}while(!exp);

	return exp;

}//end VerValidNum